#include <unistd.h>

#include <CPUSensor.hpp>
#include <Utils.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <boost/asio/read_until.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <sdbusplus/asio/connection.hpp>
#include <sdbusplus/asio/object_server.hpp>

#include <iostream>
#include <istream>
#include <limits>
#include <memory>
#include <stdexcept>
#include <string>
#include <vector>
#include <boost/asio.hpp>
#include <sdbusplus/asio/connection.hpp>
#include <sdbusplus/asio/object_server.hpp>
#include <sdbusplus/asio/property.hpp>
#include <sdbusplus/bus.hpp>
#include <sdbusplus/unpack_properties.hpp>

#include <iostream>


const std::string ServiceName = "com.otrd.cpuchangefreq";

const std::string propertyServiceName = "xyz.openbmc_project.IpmbSensor"
const std::string propertyObjectPathTempCPU0 = "/xyz/openbmc_project/sensors/temperature/CPU0_TEMP";
const std::string propertyObjectPathTempCPU1 = "/xyz/openbmc_project/sensors/temperature/CPU1_TEMP";
const std::string propertyObjectPathFreqCPU0 = "/xyz/openbmc_project/sensors/frequency/CPU0_FREQ";
const std::string propertyObjectPathFreqCPU1 = "/xyz/openbmc_project/sensors/frequency/CPU1_FREQ";

const std::string propertyInterfaceName = xyz.openbmc_project.Sensor.Value;
const std::string propertyInterfaceNameThred = xyz.openbmc_project.Sensor.Threshold.Warning;
const std::string propertyValueNameThred= "WarningHigh";
const std::string propertyValueName = "Value";
const std::string propertySetValueName = "setValue";

struct CPUTempLimitParam_T
{
	uint8_t TempEnable;
	uint8_t TempNums;
	uint32_t TempFreq;
};

struct CPUTempLimitParam FreqRangeTempParam;

uint32_t CPUSensor::fatalErrors()
{
    return fatalErrors_;
}

auto CPUSensor::logSystemErrorCode(boost::system::error_code ec)
{
    std::cerr << "Error: " << ec << "\n";
    ++fatalErrors_;
}

void CPUSensor::logException(const std::exception& e)
{
    std::cerr << "Error: " << e.what() << "\n";
    ++fatalErrors_;
}

void CPUSensor::logBadProperty(const std::string& badProperty)
{
    std::cerr << "BadProperty: " << badProperty << "\n";
    ++fatalErrors_;
}

void CPUSensor::logExpectedException(
    const sdbusplus::exception::UnpackPropertyError& error)
{
    std::cout << "As expected " << error.what() << " => "
                << error.propertyName << " is missing because "
                << error.reason << "\n";
}

void CPUSensor::asyncReadProperties()
{
    sdbusplus::asio::getProperty<uint8_t>(
        bus_, propertyServiceName, propertyObjectPathTempCPU0, propertyInterfaceName,
        propertyValueName,
        [this](boost::system::error_code ec, std::string value) {
            if (ec)
            {
                getFailed();
                return;
            }
            CPU0_Temp = value;
        });

    sdbusplus::asio::getProperty<uint8_t>(
        bus_, propertyServiceName, propertyObjectPathTempCPU1, propertyInterfaceName,
        propertyValueName,
        [this](boost::system::error_code ec, std::string value) {
            if (ec)
            {
                getFailed();
                return;
            }
            CPU1_Temp = value;
        });
    sdbusplus::asio::getProperty<uint8_t>(
        bus_, propertyServiceName, propertyObjectPathFreqCPU0, propertyInterfaceName,
        propertyValueName,
        [this](boost::system::error_code ec, std::string value) {
            if (ec)
            {
                getFailed();
                return;
            }
            CPU0_Freq = value;
        });

    sdbusplus::asio::getProperty<uint8_t>(
        bus_, propertyServiceName, propertyObjectPathFreqCPU1, propertyInterfaceName,
        propertyValueName,
        [this](boost::system::error_code ec, std::string value) {
            if (ec)
            {
                getFailed();
                return;
            }
            CPU1_Freq = value;
        });

        sdbusplus::asio::getProperty<uint8_t>(
        bus_, propertyServiceName, propertyObjectPathTempCPU0, propertyInterfaceNameThred,
        propertyValueNameThred,
        [this](boost::system::error_code ec, std::string value) {
            if (ec)
            {
                getFailed();
                return;
            }
            CPU0_Threshold = value;
        });

        sdbusplus::asio::getProperty<uint8_t>(
        bus_, propertyServiceName, propertyObjectPathTempCPU1, propertyInterfaceNameThred,
        propertyValueNameThred,
        [this](boost::system::error_code ec, std::string value) {
            if (ec)
            {
                getFailed();
                return;
            }
            CPU1_Threshold = value;
        });
}

void CPUSensor::asyncChangeProperty(uint8_t cpu0_freq,uint8_t cpu1_freq)
{
    sdbusplus::asio::setProperty(
        bus_, propertyServiceName, propertyObjectPathFreqCPU0, propertyInterfaceName,
        propertySetValueName, cpu0_freq);
    
    sdbusplus::asio::setProperty(
        bus_, demoServiceName, demoObjectPath, demoInterfaceName,
        propertyGoodbyesName, cpu1_freq);
}
    
    return 0;
}


void CPUSensor::PhytSetCPUTempLimitParam(void)
{
	if(FreqRangeTempParam.TempEnable == 0)
	{
		FreqRangeTempParam.TempEnable = 1;//进入温度调频
	}
	
	if(FreqRangeTempParam.TempNums < 12)
	{
		if(FreqRangeTempParam.TempNums < 5 && ReadFreqData.freq > 1600)
		{
			FreqRangeTempParam.TempFreq = 2100 - FreqRangeTempParam.TempNums*100;
		}
		else
		{
		   FreqRangeTempParam.TempFreq = 1850 - FreqRangeTempParam.TempNums*50;
		}
		FreqRangeTempParam.TempNums++;
	}
	
	return 0;

}

void CPUSensor::PhytSetCPUTempLimit(void)
{

    asyncReadProperties();

    if(CPU0_Temp >=CPU0_Threshold || CPU1_Temp >=CPU1_Threshold)
    {
        PhytSetCPUTempLimitParam();
		
		WriteFreqData.freq = FreqRangeTempParam.TempFreq;
		if(WriteFreqData.freq < FreqRange.min)
		{
			WriteFreqData.freq = FreqRange.min;
		}
		else
		{
			WriteFreqData.Flag = 1;
		}

        asyncChangeProperty(WriteFreqData.freq,WriteFreqData.freq);

    }
    else
    {
        if(FreqRangeTempParam.TempEnable == 1)//已开启温度调频后，温度下降到严重阈值之下，结束调控
		{
			memset(&FreqRangeTempParam,0x00,sizeof(CPUTempLimitParam_T));
		}
    }
		
    return;
}




int main(int, char**)
{
    boost::asio::io_context ioc;
    boost::asio::signal_set signals(ioc, SIGINT, SIGTERM);

    signals.async_wait(
        [&ioc](const boost::system::error_code&, const int&) { ioc.stop(); });

    auto bus = std::make_shared<sdbusplus::asio::connection>(ioc);
    auto objServer = std::make_unique<sdbusplus::asio::object_server>(bus);

    CPUSensor cpu_pro(ioc, *bus, *objServer);

    boost::asio::post(ioc,
                      [&] { cpu_pro.PhytSetCPUTempLimit(); });

    ioc.run();

    std::cout << "Fatal errors count: " << cpu_pro.fatalErrors() << "\n";

    return cpu_pro.fatalErrors();
}
